package com.xiaopeng.common.secure;


import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 脱敏工具类，支持以下类型信息的脱敏自动处理：
 * @author xiaopeng
 *
 */
public class DesensitizedUtils {

    // 字符串常量
    public static final String EMPTY = "";

    private static final int PHONE_NUMBER_LENGTH = 11;
    private static final int ID_CARD_LENGTH = 18;
    private static final int BANK_CARD_MIN_LENGTH = 16;
    private static final int BANK_CARD_MAX_LENGTH = 19;

    // 邮箱正则
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}$");


    private static final Map<Integer, String> markCacheMap = new HashMap<>() {{
        put(1, "*");
        put(2, "**");
        put(3, "***");
        put(4, "****");
        put(5, "*****");
        put(6, "******");
        put(7, "*******");
        put(8, "********");
        put(9, "*********");
    }};

    /**
     * 脱敏，使用默认的脱敏策略
     */
    public static String desensitized(String str, DesensitizationTypeEnum desensitizedType) {
        if (StringUtils.isBlank(str)) {
            return str;
        }
        String newStr = str;
        switch (desensitizedType) {
            case DesensitizationTypeEnum.CHINESE_NAME:
                newStr = chineseName(str);
                break;
            case DesensitizationTypeEnum.ID_CARD:
                newStr = idCard(str);
                break;
            case DesensitizationTypeEnum.FIXED_PHONE:
                newStr = fixedPhone(str);
                break;
            case DesensitizationTypeEnum.MOBILE_PHONE:
                newStr = mobilePhone(str);
                break;
            case DesensitizationTypeEnum.ADDRESS:
                newStr = address(str);
                break;
            case DesensitizationTypeEnum.EMAIL:
                newStr = email(str);
                break;
            case DesensitizationTypeEnum.PASSWORD:
                newStr = password(str);
                break;
            case DesensitizationTypeEnum.CAR_LICENSE:
                newStr = carLicense(str);
                break;
            case DesensitizationTypeEnum.BANK_CARD:
                newStr = bankCard(str);
                break;
            case DesensitizationTypeEnum.IPV4:
                newStr = ipv4(str, 2);
                break;
            case DesensitizationTypeEnum.IPV6:
                newStr = ipv6(str, 2);
                break;
            default:
        }
        return newStr;
    }


    public static String repeatMark(int repeat) {
        return markCacheMap.getOrDefault(repeat, "*");
    }

    /**
     * 通用脱敏方法
     * @param input 原始字符串
     * @param prefixLength 前面保留的字符数
     * @param suffixLength 后面保留的字符数
     * @return 脱敏后的字符串
     */
    public static String maskCommon(String input, int prefixLength, int suffixLength) {
        if (StringUtils.isBlank(input)) {
            return input;
        }
        int length = input.length();
        if (prefixLength + suffixLength >= length) {
            return StringUtils.repeat("*", length);
        }
        String prefix = input.substring(0, prefixLength);
        String suffix = input.substring(length - suffixLength);
        return prefix + StringUtils.repeat("*", length - prefixLength - suffixLength) + suffix;
    }

    /**
     * 中文姓名脱敏
     * @param fullName 完整姓名
     * @return 脱敏后的姓名，如：张*、欧阳**
     */
    public static String chineseName(String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return fullName;
        }
        if (fullName.length() == 1) {
            return "*";
        }
        if (fullName.length() == 2) {
            return fullName.charAt(0) + "*";
        }
        return fullName.charAt(0) + StringUtils.repeat("*", fullName.length() - 1);
    }

    /**
     * 【身份证号】前1位 和后2位
     *
     * @param idCard 身份证
     * @return 脱敏后的身份证
     */
    public static String idCard(String idCard) {
        //身份证不能为空
        if (StringUtils.isBlank(idCard)) {
            return idCard;
        }
        if (idCard.length() != ID_CARD_LENGTH) {
            return maskCommon(idCard, 3, 4); // 如果不是18位，使用通用脱敏规则
        }
        return StringUtils.overlay(idCard, StringUtils.repeat("*", 11), 3, 14);
    }

    /**
     * 【固定电话 前四位，后两位
     *
     * @param num 固定电话
     * @return 脱敏后的固定电话；
     */
    public static String fixedPhone(String num) {
        if (StringUtils.isBlank(num)) {
            return EMPTY;
        }
        return maskCommon(num, 4, num.length() - 2);
    }

    /**
     * 【手机号码】前三位，后4位，其他隐藏，比如135****2210
     *
     * @param phoneNumber 移动电话；
     * @return 脱敏后的移动电话；
     */
    public static String mobilePhone(String phoneNumber) {
        if (StringUtils.isBlank(phoneNumber)) {
            return phoneNumber;
        }
        if (phoneNumber.length() != PHONE_NUMBER_LENGTH) {
            return maskCommon(phoneNumber, 3, 4); // 如果不是11位，使用通用脱敏规则
        }
        return StringUtils.overlay(phoneNumber, "****", 3, 7);
    }

    /**
     * 【地址】只显示到地区，不显示详细地址 并将所有数字打码，比如：北京市海淀区****
     *
     * @param address       家庭住址
     * @return 脱敏后的家庭地址
     */
    public static String address(String address) {
        if (StringUtils.isBlank(address)) {
            return address;
        }
        if (address.length() <= 4) {
            return address.charAt(0) + "***";
        }
        return maskCommon(address, 6, 0).replaceAll("\\d", "*");
    }

    /**
     * 【电子邮箱】邮箱前缀仅显示第一个字母，前缀其他隐藏，用星号代替，@及后面的地址显示，比如：d**@126.com
     *
     * @param email 邮箱
     * @return 脱敏后的邮箱
     */
    public static String email(String email) {
        if (StringUtils.isBlank(email)) {
            return email;
        }

        if (!EMAIL_PATTERN.matcher(email).matches()) {
            return maskCommon(email, 1, 1); // 如果不是有效邮箱格式，使用通用脱敏规则
        }
        int atIndex = email.indexOf("@");
        if (atIndex <= 1) {
            return email.charAt(0) + "***" + email.substring(atIndex);
        }
        String prefix = email.substring(0, atIndex);
        String suffix = email.substring(atIndex);
        return prefix.charAt(0) + "***" + prefix.charAt(prefix.length() - 1) + suffix;
    }

    /**
     * 【密码】密码的全部字符都用*代替，比如：******
     *
     * @param password 密码
     * @return 脱敏后的密码
     */
    public static String password(String password) {
        return "******";
    }

    /**
     * 【中国车牌】车牌中间用*代替
     * eg1：null       -》 ""
     * eg1：""         -》 ""
     * eg3：苏D40000   -》 苏D4***0
     * eg4：陕A12345D  -》 陕A1****D
     * eg5：京A123     -》 京A123     如果是错误的车牌，不处理
     *
     * @param carLicense 完整的车牌号
     * @return 脱敏后的车牌
     */
    public static String carLicense(String carLicense) {
        if (StringUtils.isBlank(carLicense)) {
            return EMPTY;
        }
        // 普通车牌
        if (carLicense.length() == 7) {
            carLicense = maskCommon(carLicense, 3, 6);
        } else if (carLicense.length() == 8) {
            // 新能源车牌
            carLicense = maskCommon(carLicense, 3, 7);
        }
        return carLicense;
    }

    /**
     * 银行卡号脱敏
     * eg: 1101 **** **** **** 3256
     *
     * @param bankCardNumber 银行卡号
     * @return 脱敏之后的银行卡号
     * @since 5.6.3
     */
    public static String bankCard(String bankCardNumber) {
        if (StringUtils.isBlank(bankCardNumber)) {
            return bankCardNumber;
        }
        int length = bankCardNumber.length();
        if (length < BANK_CARD_MIN_LENGTH || length > BANK_CARD_MAX_LENGTH) {
            return maskCommon(bankCardNumber, 6, 4); // 如果不符合银行卡号长度，使用通用脱敏规则
        }
        return StringUtils.overlay(bankCardNumber, StringUtils.repeat("*", length - 8), 6, length - 4);
    }

    /**
     * IPv4脱敏，如：脱敏前：192.0.2.1；脱敏后：192.*.*.*。
     *
     * @param ipv4 IPv4地址
     * @return 脱敏后的地址
     */
    public static String ipv4(String ipv4, int keepSegments) {
        if (StringUtils.isBlank(ipv4)) {
            return ipv4;
        }
        String[] parts = ipv4.split("\\.");
        if (parts.length != 4) {
            return ipv4;
        };
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            sb.append(i < keepSegments ? parts[i] : "***");
            if (i < 3) sb.append(".");
        }
        return sb.toString();
    }

    /**
     * IPv4脱敏，如：脱敏前：2001:0db8:86a3:08d3:1319:8a2e:0370:7344；脱敏后：2001:*:*:*:*:*:*:*
     *
     * @param ipv6 IPv4地址
     * @return 脱敏后的地址
     */
    public static String ipv6(String ipv6, int keepSegments) {
        if (ipv6 == null) return null;
        String[] parts = ipv6.split(":");
        if (parts.length < 4){
            return ipv6;
        };
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            sb.append(i < keepSegments ? parts[i] : "****");
            if (i < parts.length - 1) sb.append(":");
        }
        return sb.toString();
    }
}
